﻿using System;
using System.Collections.Generic;
using GeoAPI.Geometries;
using NetTopologySuite.Algorithm;
using NetTopologySuite.Geometries;

namespace NetTopologySuite.Triangulate.QuadEdge
{
	public class QuadEdgeTriangle
	{
		public static IList<QuadEdgeTriangle> CreateOn(QuadEdgeSubdivision subdiv)
		{
			QuadEdgeTriangle.QuadEdgeTriangleBuilderVisitor quadEdgeTriangleBuilderVisitor = new QuadEdgeTriangle.QuadEdgeTriangleBuilderVisitor();
			subdiv.VisitTriangles(quadEdgeTriangleBuilderVisitor, false);
			return quadEdgeTriangleBuilderVisitor.GetTriangles();
		}

		public static bool Contains(Vertex[] tri, Coordinate pt)
		{
			Coordinate[] ring = new Coordinate[]
			{
				tri[0].Coordinate,
				tri[1].Coordinate,
				tri[2].Coordinate,
				tri[0].Coordinate
			};
			return CGAlgorithms.IsPointInRing(pt, ring);
		}

		public static bool Contains(QuadEdge[] tri, Coordinate pt)
		{
			Coordinate[] ring = new Coordinate[]
			{
				tri[0].Orig.Coordinate,
				tri[1].Orig.Coordinate,
				tri[2].Orig.Coordinate,
				tri[0].Orig.Coordinate
			};
			return CGAlgorithms.IsPointInRing(pt, ring);
		}

		public static IGeometry ToPolygon(Vertex[] v)
		{
			Coordinate[] coordinates = new Coordinate[]
			{
				v[0].Coordinate,
				v[1].Coordinate,
				v[2].Coordinate,
				v[0].Coordinate
			};
			GeometryFactory geometryFactory = new GeometryFactory();
			ILinearRing shell = geometryFactory.CreateLinearRing(coordinates);
			return geometryFactory.CreatePolygon(shell, null);
		}

		public static IGeometry ToPolygon(QuadEdge[] e)
		{
			Coordinate[] coordinates = new Coordinate[]
			{
				e[0].Orig.Coordinate,
				e[1].Orig.Coordinate,
				e[2].Orig.Coordinate,
				e[0].Orig.Coordinate
			};
			GeometryFactory geometryFactory = new GeometryFactory();
			ILinearRing shell = geometryFactory.CreateLinearRing(coordinates);
			return geometryFactory.CreatePolygon(shell, null);
		}

		public QuadEdgeTriangle(QuadEdge[] edge)
		{
			this._edge = (QuadEdge[])edge.Clone();
			for (int i = 0; i < 3; i++)
			{
				edge[i].Data = this;
			}
		}

		public object Data { get; set; }

		public void Kill()
		{
			this._edge = null;
		}

		public bool IsLive()
		{
			return this._edge != null;
		}

		public QuadEdge[] GetEdges()
		{
			return this._edge;
		}

		public QuadEdge GetEdge(int i)
		{
			return this._edge[i];
		}

		public Vertex GetVertex(int i)
		{
			return this._edge[i].Orig;
		}

		public Vertex[] GetVertices()
		{
			Vertex[] array = new Vertex[3];
			for (int i = 0; i < 3; i++)
			{
				array[i] = this.GetVertex(i);
			}
			return array;
		}

		public Coordinate GetCoordinate(int i)
		{
			return this._edge[i].Orig.Coordinate;
		}

		public int GetEdgeIndex(QuadEdge e)
		{
			for (int i = 0; i < 3; i++)
			{
				if (this._edge[i] == e)
				{
					return i;
				}
			}
			return -1;
		}

		public int GetEdgeIndex(Vertex v)
		{
			for (int i = 0; i < 3; i++)
			{
				if (this._edge[i].Orig == v)
				{
					return i;
				}
			}
			return -1;
		}

		public void GetEdgeSegment(int i, LineSegment seg)
		{
			seg.P0 = this._edge[i].Orig.Coordinate;
			int num = (i + 1) % 3;
			seg.P1 = this._edge[num].Orig.Coordinate;
		}

		public Coordinate[] GetCoordinates()
		{
			Coordinate[] array = new Coordinate[4];
			for (int i = 0; i < 3; i++)
			{
				array[i] = this._edge[i].Orig.Coordinate;
			}
			array[3] = new Coordinate(array[0]);
			return array;
		}

		public bool Contains(Coordinate pt)
		{
			Coordinate[] coordinates = this.GetCoordinates();
			return CGAlgorithms.IsPointInRing(pt, coordinates);
		}

		public IGeometry GetGeometry(GeometryFactory fact)
		{
			ILinearRing shell = fact.CreateLinearRing(this.GetCoordinates());
			return fact.CreatePolygon(shell, null);
		}

		public override string ToString()
		{
			return this.GetGeometry(new GeometryFactory()).ToString();
		}

		public bool IsBorder()
		{
			for (int i = 0; i < 3; i++)
			{
				if (this.GetAdjacentTriangleAcrossEdge(i) == null)
				{
					return true;
				}
			}
			return false;
		}

		public bool IsBorder(int i)
		{
			return this.GetAdjacentTriangleAcrossEdge(i) == null;
		}

		public QuadEdgeTriangle GetAdjacentTriangleAcrossEdge(int edgeIndex)
		{
			return (QuadEdgeTriangle)this.GetEdge(edgeIndex).Sym.Data;
		}

		public int GetAdjacentTriangleEdgeIndex(int i)
		{
			return this.GetAdjacentTriangleAcrossEdge(i).GetEdgeIndex(this.GetEdge(i).Sym);
		}

		public IList<QuadEdgeTriangle> GetTrianglesAdjacentToVertex(int vertexIndex)
		{
			List<QuadEdgeTriangle> list = new List<QuadEdgeTriangle>();
			QuadEdge edge = this.GetEdge(vertexIndex);
			QuadEdge quadEdge = edge;
			do
			{
				QuadEdgeTriangle quadEdgeTriangle = (QuadEdgeTriangle)quadEdge.Data;
				if (quadEdgeTriangle != null)
				{
					list.Add(quadEdgeTriangle);
				}
				quadEdge = quadEdge.ONext;
			}
			while (quadEdge != edge);
			return list;
		}

		public QuadEdgeTriangle[] GetNeighbours()
		{
			QuadEdgeTriangle[] array = new QuadEdgeTriangle[3];
			for (int i = 0; i < 3; i++)
			{
				array[i] = (QuadEdgeTriangle)this.GetEdge(i).Sym.Data;
			}
			return array;
		}

		private QuadEdge[] _edge;

		private class QuadEdgeTriangleBuilderVisitor : ITriangleVisitor
		{
			public void Visit(QuadEdge[] edges)
			{
				this._triangles.Add(new QuadEdgeTriangle(edges));
			}

			public List<QuadEdgeTriangle> GetTriangles()
			{
				return this._triangles;
			}

			private readonly List<QuadEdgeTriangle> _triangles = new List<QuadEdgeTriangle>();
		}
	}
}
